/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved.
 * Description: Entry point of liblinux backend
 * Author: Huawei OS Kernel Lab
 * Create: Wed Jul 10 16:58:35 2019
 */

/*
 * Avoid including RO_AFTER_INIT_DATA twice. which cause the value of
 * __start___jump_label and __stop___jump_label is reassigned.
 */
#define RO_AFTER_INIT_DATA

#include <asm-generic/vmlinux.lds.h>
#include <asm/cache.h>
#include <asm/page.h>
#include <asm/memory.h>

#define PT_GNU_RELRO	0x6474e552
#define PT_GNU_STACK	0x6474e551

PHDRS
{
	text PT_LOAD FILEHDR PHDRS ;
	initdata PT_LOAD ;
	data PT_LOAD ;
	tls PT_TLS FLAGS(4);
	module_rsvd PT_LOAD FLAGS(0);
	dynamic PT_DYNAMIC ;
	note PT_NOTE ;
	stack PT_GNU_STACK FLAGS(6);
	relro PT_GNU_RELRO FLAGS(4);
}

SECTIONS
{
	. = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
	.note.gnu.build-id  : { *(.note.gnu.build-id) } : text : note
	.hash           : { *(.hash) } : text
	.gnu.hash       : { *(.gnu.hash) }
	.dynsym         : { *(.dynsym) }
	.dynstr         : { *(.dynstr) }
	.gnu.version    : { *(.gnu.version) }
	.gnu.version_d  : { *(.gnu.version_d) }
	.gnu.version_r  : { *(.gnu.version_r) }
	.rela.dyn       :
	{
		*(.rela.init)
			*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
			*(.rela.fini)
			*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
			*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
			*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
			*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
			*(.rela.ctors)
			*(.rela.dtors)
			*(.rela.got)
			*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
			*(.rela.ifunc)
	}
	.rela.plt       :
	{
		*(.rela.plt)
			*(.rela.iplt)
	}
	.plt            : ALIGN(16) { *(.plt) *(.iplt) }

	.text : ALIGN(PAGE_SIZE) {
		_text = .;
		_stext = .;
			IRQENTRY_TEXT
			SOFTIRQENTRY_TEXT
			TEXT_TEXT
			SCHED_TEXT
			LOCK_TEXT
			*(.__liblinux_unimpl)
			*(.text.override)
			*(.fixup)
		. = ALIGN(16);
	}
	. = ALIGN(PAGE_SIZE);
	_etext = .;

	.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }

	. = ALIGN(PAGE_SIZE);
	__init_begin = .;
	__init_text_begin = .;
	INIT_TEXT_SECTION(8)
	. = ALIGN(4);
	.altinstructions : {
		__alt_instructions = .;
		*(.altinstructions)
		__alt_instructions_end = .;
	}
	.altinstr_replacement : {
		*(.altinstr_replacement)
	}
	. = ALIGN(PAGE_SIZE);
	__init_text_end = .;
	__init_data_begin = .;
	INIT_DATA_SECTION(8) : initdata
	.extralib.init.data : {
        __vendor_hook_initcall_start = .;
        *(.liblinux.vh.init.data)
        __vendor_hook_initcall_end = .;
		__extralib_initcall_start = .;
		*(.extralib.init.data)
		__extralib_initcall_end = .;
	}
	.fixup.boot_param : {
		__fixup_boot_param_start = .;
		*(.fixup.boot_param)
		__fixup_boot_param_end = .;
	}
	PERCPU_SECTION(L1_CACHE_BYTES)
	. = ALIGN(PAGE_SIZE);
	__initdata_end = .;
	__init_end = .;

	/*
	 * The ".data.ro_after_init" section must be placed before DATA_SEGMENT_ALIGN,
	 * otherwise it will be included in RELRO segment which is NOT writable after
	 * relocation.
	 */
	.data.ro_after_init : {
		. = ALIGN(8);
		__start_ro_after_init = .;
		*(.data..ro_after_init .data.rel.ro.*)
		JUMP_TABLE_DATA
		STATIC_CALL_DATA
		__end_ro_after_init = .;
	}

	. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));

	/* RELRO Segment Start */
	.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
	/* TLS Segment */
	.tdata		: { *(.tdata .tdata.* .gnu.linkonce.td.*) } : data : relro : tls
	.tbss		: { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } : tls
	.init_array	: { KEEP (*(.init_array)) } : data : relro
	/* vmlinux's RO_DATA is relro */
	.data.rel.ro	: {
		*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)
		*(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*)
#ifdef CONFIG_LIBLINUX_EXTRACT_KALLSYMS
		. = ALIGN(PAGE_SIZE); __start_kallsyms = .;*(.kallsyms) __end_kallsyms = .;
#endif
	} : data : relro
	.dynamic	: { *(.dynamic) } : dynamic : data : relro
	.got		: { *(.got) *(.igot) } : data : relro
	RO_DATA(PAGE_SIZE)
	. = DATA_SEGMENT_RELRO_END (24, .);

	.got.plt	: { *(.got.plt) *(.igot.plt) } : data

	_data = .;
	_sdata = .;
	RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_ALIGN)
	.data : { *(.data.rel) *(.data.rel.local) }
	_edata = .;

	BSS_SECTION(0, 0, 0)

	_end = .;
	. = DATA_SEGMENT_END (.);

	/* for jiffies */
	.liblinux.self.jiffies : {
#ifdef __ARMEB__
		jiffies = jiffies_64 + 4;
#else
		jiffies = jiffies_64;
#endif
	}

	/* for module rsvd */
	. = ALIGN(CONSTANT(COMMONPAGESIZE));
	.liblinux.modules.rsvd ALIGN(CONSTANT(COMMONPAGESIZE)) (NOLOAD) : {
		__liblinux_modules_pool = .;
		. = . + (1 << CONFIG_LIBLINUX_MODULES_RSVD_BITS);
		__liblinux_modules_pool_end = .;
	} : module_rsvd

	.head.text : { HEAD_TEXT }
	ASSERT(SIZEOF(.head.text) == 0, "Unexpected early init text (.head.text) detected!")

	DISCARDS

	/* ARM need extra DISCARD */
	#ifdef CONFIG_ARM
	/DISCARD/ : {
		*(.ARM.exidx.exit.text)
		*(.ARM.extab.exit.text)
		*(.ARM.exidx.text.exit)
		*(.ARM.extab.text.exit)
	}
	#endif
}
